<template>
  <!-- 
  组件名称: TabsLayout
  功能描述: 快捷页签,包含多个标签页
  业务归属: layout-default 默认布局
   -->

  <!-- 
  v-model="currentTab.name"：双向绑定当前激活的标签页名称
  作用：将当前激活的标签页名称与 currentTab.name 进行双向绑定

  type="card"：标签页类型
  作用：设置标签页的样式为卡片式
    
  closable：标签页可关闭
  作用：允许用户关闭标签页


  @tab-click="handleClick"：标签页点击事件
  作用：当用户点击标签页时,触发 handleClick 函数

  @tab-remove="remove"：标签页关闭事件
  作用：当用户关闭标签页时,触发 remove 函数
    -->
  <el-tabs
    v-model="currentTab.name"
    type="card"
    class="demo-tabs"
    closable
    @tab-click="handleClick"
    @tab-remove="remove"
  >
    <!-- 
    循环项
    v-for="item in tabs"：循环 tabs 数组,每个元素代表一个标签页
    :key="item.name"：为每个标签页设置唯一的 key,使用 item.name 作为 key
    :label="item.name"：设置标签页的名称,使用 item.name 作为标签页的名称
    :name="item.name"：设置标签页的唯一标识,使用 item.name 作为标签页的名称,同时跟当前页签高亮逻辑有关
     -->
    <el-tab-pane
      v-for="item in tabs"
      :key="item.name"
      :label="item.name"
      :name="item.name"
    >
      <template #label>
        <span class="custom-tabs-label">
          <!-- 图标 -->
          <el-icon>
            <component :is="item.icon" />
          </el-icon>
          <!-- 文本 -->
          <span>&nbsp;{{ item.name }}</span>
        </span>
      </template>
    </el-tab-pane>
  </el-tabs>
  <!-- 路由视图 -->
  <router-view v-slot="{ Component }">
    <!-- 如果当前路由需要缓存 -->
    <keep-alive>
      <component :is="Component" :key="$route.name" v-if="$route.meta.keepAlive" />
    </keep-alive>
    <!-- 如果当前路由不需要缓存 -->
    <component :is="Component" :key="$route.name" v-if="!$route.meta.keepAlive" />
  </router-view>
</template>

<script setup lang="ts">
import { storeToRefs } from "pinia";
import { useRouter, useRoute } from "vue-router";
const router = useRouter();

/**
 * 功能作用:刷新页面后,保持当前激活的标签页
 * 逻辑描述:首先要知道当前页面的路由,然后在 pinina 文件 - auth.ts 里的 menu 数组中找到对应的路由信息,然后添加到快捷页签数组中
 *
 * 引入 pinia 文件 - tabs.ts ,拿到 useTabsStore 快捷页签实例
 * 声明实例,拿到里面的属性和方法
 * 拿到 tabsStore 实例 里的 setCurrentTab 函数, 用于设置当前激活的标签页
 * 拿到 tabsStore 实例 里的 tabs 和 currentTab 属性, 用于获取 快捷页签数组 和 当前激活高亮的标签页
 * 拿到 tabsStore 实例 里的 addTab 函数, 用于添加新的标签页
 *
 * 引入 pinia 文件 - auth.ts ,拿到 useUserStore 用户信息实例
 * 声明实例,拿到里面的属性和方法
 * 拿到 userStore 实例 里的 menu 属性, 用于获取菜单数组,存储所有的菜单信息
 *
 * 引入 vue-router 里的 useRoute , 拿到当前路由实例
 * 声明 route 实例,拿到里面的属性和方法
 *
 * 声明一个 findObjectByUrl 函数, 有两个参数,分别是菜单数组和路由地址,用于查找匹配的菜单对象
 * 这个函数会遍历菜单数组,如果找到匹配的路由地址,就返回对应的菜单对象
 * 如果没有找到传入的路由地址,就再次判断是否有子菜单,如果有,就递归调用 findObjectByUrl 函数
 * 如果找到匹配的路由地址,就返回对应的菜单对象
 * 如果没有找到,就返回 null
 *
 * 声明 name, url, icon 变量, 用于接收 findObjectByUrl 函数返回的菜单对象
 * 调用 addTab 函数,传入 name, url, icon 作为参数,用于添加当前路由对应的标签页
 * 调用 setCurrentTab 函数,传入 name, url 作为参数,用于设置当前高亮的标签页
 */
import { useTabsStore } from "@/store/tabs";
const tabsStore = useTabsStore();
const { setCurrentTab } = tabsStore;
const { tabs, currentTab } = storeToRefs(tabsStore);
const { addTab } = tabsStore;

import { useUserStore } from "@/store/auth";
const userStore = useUserStore();
const { menu } = storeToRefs(userStore);

const route = useRoute();
function findObjectByUrl(arr: any[], url: string) {
  for (const item of arr) {
    if (item.url === url) {
      return item;
    }

    if (item.children) {
      const found: any = findObjectByUrl(item.children, url);
      if (found) {
        return found;
      }
    }
  }

  return null;
}
const { name, url, icon } = findObjectByUrl(menu.value, route.path) || {};
addTab(name, url, icon);
setCurrentTab(name, url);

/**
 * 功能作用:处理标签页的点击事件
 * 逻辑描述:当用户点击标签页时,跳转到当前标签页对应的路由
 *
 * 参数里的 index , 表示当前标签页的索引,是从函数里默认参数 tab 里结构出来的
 * 通过 tabs.value[index].url 获取当前标签页对应的路由地址
 * 调用 router.push 方法,跳转到当前标签页对应的路由
 * 调用 setCurrentTab 函数,传入 tabs.value[index].name 和 tabs.value[index].url 作为参数,用于设置当前高亮的标签页
 */
const handleClick = ({ index }: { index: number }) => {
  router.push(tabs.value[index].url); // 跳转到当前标签页对应的路由
  setCurrentTab(tabs.value[index].name, tabs.value[index].url); // 设置当前高亮的标签页
};

/**
 * 功能作用:处理标签页的关闭事件
 * 逻辑描述:当用户关闭标签页时,删除当前标签页
 *
 * 到 tabsStore 实例 里的 removeTab 函数, 用于删除当前标签页
 * 判断传入的参数 TabPaneName(当前面板的名字) 是否和 currentTab(当前激活的标签页) 相同,就是判断当前关闭的标签页是否是当前激活高亮的标签页
 * 如果相同,就调用 removeTab 函数,删除当前标签页,并且跳转到当前激活的标签页对应的路由,注意: 此时 currentTab 里的数据是被删除后重新赋值的
 * 如果不相同,就代码当前要删除的标签页,不是高亮的标签页面,就不需要跳转,直接执行 removeTab 函数,删除当前标签页
 */
const { removeTab } = tabsStore;
const remove = (TabPaneName: string) => {
  console.log(currentTab.value.name);
  if (currentTab.value.name == TabPaneName) {
    removeTab(TabPaneName);
    router.push(currentTab.value.url);
  } else {
    removeTab(TabPaneName);
  }
};
</script>

<style scoped lang="less">
.demo-tabs {
  :deep(.is-active) {
    background: rgb(47 80 157) !important;
    color: #fff !important;
  }
}
</style>
